// phalanx at.hpp.cu header file

// Copyright (c) 2010 - 2011 Kohei Takahashi (Flast).
// Distributed under the MIT license. for more detail see COPYING.

#ifndef IG_PHALANX_FUNCTIONAL_AT_HPP_CU_ONCE_
#define IG_PHALANX_FUNCTIONAL_AT_HPP_CU_ONCE_

#include <phalanx/config.hpp.cu>

#include <cstddef>

#include <phalanx/type_traits/builtin_traits.hpp.cu>

namespace phalanx
{

namespace at_detail
{

template < typename V,
  typename vector_type_traits< V >::value_type V::*mem_ptr >
struct _vec_at_impl
{
    typedef vector_type_traits< V > traits_type;

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    static typename traits_type::const_reference
    impl( const V &v )
    { return v.*mem_ptr; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    static typename traits_type::reference
    impl( V &v )
    { return v.*mem_ptr; }
};

template < int, typename >
struct _vec_at;

template < typename V >
struct _vec_at< 0, V >
  : public _vec_at_impl< V, &V::x > {};

template < typename V >
struct _vec_at< 1, V >
  : public _vec_at_impl< V, &V::y > {};

template < typename V >
struct _vec_at< 2, V >
  : public _vec_at_impl< V, &V::z > {};

template < typename V >
struct _vec_at< 3, V >
  : public _vec_at_impl< V, &V::w > {};

} // namespace at_detail

template < int idx, typename V >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename vector_type_traits< V >::reference
at( V &v )
{ return at_detail::_vec_at< idx, V >::impl( v ); }

template < int idx, typename V >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename vector_type_traits< V >::const_reference
at( const V &v )
{ return at_detail::_vec_at< idx, V >::impl( v ); }

template < int idx, typename T, ::std::size_t n_ >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
T &
at( T ( &a )[ n_ ] )
{ return a[ idx ]; }

} // namespace phalanx

#endif // IG_PHALANX_FUNCTIONAL_AT_HPP_CU_ONCE_

